跳到主要内容

Linux 的进程是什么

我们如何产生一个进程呢?就是 “执行一个程序或指令” 就可以触发一个事件而取得一个 PID

如上图所示,程序一般是放置在实体磁盘中,然后通过使用者的执行来触发。触发后会载入到内存中成为一个个体,那就是进程。 为了操作系统可管理这个进程,因此进程有给予执行者的权限/属性等参数,并包括进程所需要的指令码与数据或文件数据等, 最后再给予一个 PID 。系统就是通过这个 PID 来判断该 process 是否具有权限进行工作的。

子进程与父进程

用户使用的 Bash 其实也是一个进程如下:(这里使用的是 zsh)

$ ps
PID TTY TIME CMD
29319 pts/2 00:00:06 zsh
31058 pts/2 00:00:00 ps

子进程就是所谓的 “衍生出来的程序”,例如在当前 Shell 下再执行 bash 命令开辟的新 shell 就是一个子进程

$ ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 1000 29319 29318 0 80 0 - 4157 sigsus pts/2 00:00:06 zsh
0 S 1000 30996 29319 0 80 0 - 2502 do_wai pts/2 00:00:00 bash
0 R 1000 31002 30996 0 80 0 - 2635 - pts/2 00:00:00 ps

可以注意到 bash 的 PPID 和 zsh 的 PID 一样,这个 PPID 就是 Parent PID

所以可以以此编写脚本,打印它们的树状结构

#!/bin/bash
pidtree() {
echo -n $1 " "
for _child in $(ps -o pid --no-headers --ppid $1); do
echo -n $_child `pidtree $_child` " "
done
}

# PID
ps f `pidtree 4378`

output

 4378 ?        Ss     0:10 SCREEN
4897 pts/16 Ss 0:00 \_ -/bin/bash
25667 pts/16 S+ 0:00 | \_ git diff
25669 pts/16 S+ 0:00 | \_ less -FRSX
11118 pts/32 Ss+ 0:00 \_ -/bin/bash
11123 pts/32 S+ 0:00 \_ vi

fork and exec 进程调用的流程

其实子进程与父进程之间的关系还挺复杂的,最大的复杂点在于进程互相之间的调用。在 Linux 的进程调用通常称为 fork-and-exec 的流程 !进程都会借由父进程复制 (fork) 的方式产生一个一模一样的子进程, 然后被复制出来的子进程再以 exec 的方式来执行实际要进行的进程,最终就成为一个子进程。 整个流程有点像下面这张图:

系统先以 fork 的方式复制一个与父进程相同的暂存进程,这个进程与父进程唯一的差别就是 PID 不同! 但是这个暂存进程还会多一个 PPID 的参数,PPID 如前所述,就是父进程的 PID;

然后暂存进程开始以 exec 的方式载入实际要执行的程序,以上述图示来讲,新的程序名称为 qqq ,最终子进程的程序码就会变成 qqq 了

子进程一旦开始运行,虽然它继承了父进程的一切数据,但实际上数据却已经分开,相互之间不再有影响了,也就是说,它们之间不再共享任何数据了。

常驻在内存的进程

常驻在内存当中的程序通常都是负责一些系统所提供的功能以服务使用者各项任务,因此这些常驻程序就会被我们称为:服务 (daemon)。

References

How can i recursively get all child process for a given pid 什么是程序 (process) fork,exec,vfork和线程池